package com.zzyq.pc.utils;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;

public class JsonUtils {

    public static enum JsonResult {

        DEFAULT, STRING_AS_NULL

    }

    private static Logger log = LoggerFactory.getLogger(JsonUtils.class);

    private static ObjectMapper mapper = new ObjectMapper();

    private static ObjectMapper stringAsNullMapper = new ObjectMapper();

    static {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        mapper.setDateFormat(format);

        // SimpleModule module = new SimpleModule();
        // module.addSerializer(BigDecimal.class, new ToStringSerializer());
        //
        // mapper.registerModule(module);
        stringAsNullMapper.setDateFormat(format);
        stringAsNullMapper.setSerializerProvider(new CustomNullStringSerializerProvider());
    }

    /**
     * 将不含日期时间格式的Java对象系列化为Json资料格式
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String ObjectToString(Object pObject) {
        if (pObject == null) {
            return null;
        }

        String jsonString = "[]";
        if (pObject != null) {
            try {
                jsonString = mapper.writeValueAsString(pObject);
            } catch (JsonProcessingException e) {
                log.warn("转化json失败", e);
            }
        }
        return pObject.getClass().getSimpleName() + " -->:" + jsonString;
    }

    /**
     * 将不含日期时间格式的Java对象系列化为Json资料格式
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String toString(Object pObject) {
        if (pObject == null) {
            return null;
        }

        String jsonString = "[]";
        if (pObject != null) {
            try {
                jsonString = mapper.writeValueAsString(pObject);
            } catch (JsonProcessingException e) {
                log.warn("转化json失败", e);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    public static final String toString(Object pObject, JsonResult jsonResult) {

        if (pObject == null) {
            return null;
        }

        ObjectMapper mapperToUse = null;

        switch (jsonResult) {
        case STRING_AS_NULL:
            mapperToUse = stringAsNullMapper;
            break;
        default:
            mapperToUse = mapper;
        }

        String jsonString = "[]";
        if (pObject != null) {
            try {
                jsonString = mapperToUse.writeValueAsString(pObject);
            } catch (JsonProcessingException e) {
                log.warn("转化json失败", e);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将含有日期时间格式的Java对象系列化为Json资料格式<br>
     * Json-Lib在处理日期时间格式是需要实现其JsonValueProcessor接口,所以在这里提供一个重载的方法对含有<br>
     * 日期时间格式的Java对象进行序列化
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String toString(Object pObject, String pFormatString) {

        if (pObject == null) {
            return null;
        }

        String jsonString = "[]";
        if (pObject != null) {
            try {
                ObjectMapper tempObjectMapper = new ObjectMapper();
                DateFormat format = new SimpleDateFormat(pFormatString);
                tempObjectMapper.setDateFormat(format);
                jsonString = tempObjectMapper.writeValueAsString(pObject);
            } catch (JsonProcessingException e) {
                log.warn("转化json失败", e);
            }
        }
        if (log.isDebugEnabled()) {
           // log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    public static final <T> T toObject(String json, Class<T> clazz) {

        try {
            return mapper.readValue(json, clazz);
        } catch (IOException e) {
            log.warn("把字符串转为对象失败", e);
            return null;
        }

    }

    public static class CustomNullStringSerializerProvider extends DefaultSerializerProvider {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        // A couple of constructors and factory methods to keep the compiler
        // happy
        public CustomNullStringSerializerProvider() {
            super();
        }

        public CustomNullStringSerializerProvider(CustomNullStringSerializerProvider provider,
                SerializationConfig config, SerializerFactory jsf) {
            super(provider, config, jsf);
        }

        @Override
        public CustomNullStringSerializerProvider createInstance(SerializationConfig config, SerializerFactory jsf) {
            return new CustomNullStringSerializerProvider(this, config, jsf);
        }

        // This is the interesting part. When the property has a null value it
        // will call this method to get the
        // serializer for that null value. At this point, we have the
        // BeanProperty, which contains information about
        // the field that we are trying to serialize (including the type!) So we
        // can discriminate on the type to determine
        // which serializer is used to output the null value.
        @Override
        public JsonSerializer<Object> findNullValueSerializer(BeanProperty property) throws JsonMappingException {
            if (property.getType().getRawClass().equals(String.class)) {
                return EmptyStringSerializer.INSTANCE;
            } else {
                return super.findNullValueSerializer(property);
            }
        }
    }

    // This is our fancy serializer that takes care of writing the value desired
    // in the case of a null string. We could
    // write whatever we want in here, but in order to maintain backward
    // compatibility we choose the empty string
    // instead of something like "joel is awesome."
    public static class EmptyStringSerializer extends JsonSerializer<Object> {
        public static final JsonSerializer<Object> INSTANCE = new EmptyStringSerializer();

        private EmptyStringSerializer() {
        }

        // Since we know we only get to this seralizer in the case where the
        // value is null and the type is String, we can
        // do our handling without any additional logic and write that empty
        // string we are so desperately wanting.
        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonProcessingException {

            jsonGenerator.writeString("");
        }

    }

}
